/*
 *  Copyright (c) 2022 ZhuHai Jieli Technology Co.,Ltd.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "gpio.h"
#include "spinlock.h"
#include "power/p33.h"
#ifndef EINVAL
#define EINVAL      22  /* Invalid argument */
#endif
#define     CONFIG_GPIO_RTC 0

#define AT_GPIO_RAM             AT(.gpio_ram)

// *INDENT-OFF*
#if CONFIG_GPIO_RTC
#include "p33_interface.h"
#else
#define     PORTR_HD(gpio, value)    (-EINVAL)
#define     PORTR_HD0(gpio, value)    (-EINVAL)
#define     PORTR_DIR(gpio, value)    (-EINVAL)
#define     PORTR_PD(gpio, value)  (-EINVAL)
#define     PORTR_PU(gpio, value)  (-EINVAL)
#define     PORTR_DIE(gpio, value) (-EINVAL)
#define     PORTR_OUT(gpio, value) (-EINVAL)
#define     PORTR_IN(gpio)  (-EINVAL)
#define     PORTR_DIEH(gpio, value)    (-EINVAL)
#endif

#define     CONFIG_GPIO_SPIN_LOCK 0

#if CONFIG_GPIO_SPIN_LOCK
#else
#define spin_lock(lock)
#define spin_unlock(lock)
#endif
// *INDENT-ON*

#define CHIP_VER_A        0x0
#define CHIP_VER_B        0x1
#define CHIP_VER_D        0x3
#define CHIP_VER        (JL_SYSTEM->CHIP_ID & 0xF)

extern void audio_adc_mic_ctl(u8 en);
void __attribute__((weak)) audio_adc_mic_ctl(u8 en)
{
    static char mic_ctl = 0xff;
    if (mic_ctl == en) {
        return;
    }
    mic_ctl = en;
    if (en) {
        JL_ANA->DAA_CON3 |= BIT(16);              // VCM_EN_11v
        JL_ANA->DAA_CON0 |= (BIT(0) | BIT(1));  // AUDIO_VBIAS_EN_11V AUDIO_IBIAS_EN_11v

        /* AUDCTADC_VREF_EN_11V    AUDCTADC_EN_11V */
        JL_ANA->ADA_CON0 = BIT(17) | BIT(16);

        JL_ANA->ADA_CON2 &= ~BIT(20);     // MIC_BIAS_SEL_11v
        JL_ANA->ADA_CON2 |=  BIT(14);     // MICLDO_EN_11v
        SFR(JL_ANA->ADA_CON2,  21,  5,  0); // MIC_BIAS_RSEL_11v[4:0]
        SFR(JL_ANA->ADA_CON2,  16,  2,  2); // MICLDO_VOLSEL_11V[1:0]

        JL_ANA->ADA_CON4 &= ~BIT(17);     // DAC_2_MICBIAS_EN_11v
        JL_ANA->ADA_CON4 |= BIT(16);      // VCM_2_MICBIAS_EN_11v
        JL_ANA->ADA_CON4 |= BIT(20);      // MIC_EN_11V
    } else {
        JL_ANA->DAA_CON3 &= ~BIT(16);              // VCM_EN_11v
        JL_ANA->DAA_CON0 &= ~(BIT(0) | BIT(1));  // AUDIO_VBIAS_EN_11V AUDIO_IBIAS_EN_11v
        JL_ANA->ADA_CON0 &= ~(BIT(16) | BIT(17));    // AUDCTADC_VREF_EN_11V AUDCTADC_EN_11V
        JL_ANA->ADA_CON2 &= ~BIT(14);               // MICLDO_EN_11V
        JL_ANA->ADA_CON4 &= ~(BIT(16) | BIT(20));   // VCM_2_MICBIAS_EN_11v MIC_EN_11V
    }
}

AT_GPIO_RAM
static const u32 gpio_regs[] = {
    (u32) JL_PORTA,
    (u32) JL_PORTB,
    (u32) JL_PORTC,
    (u32) JL_PORTD,
};

#define __gpio_mask(gpio) \
    BIT((gpio) % IO_GROUP_NUM)

AT_GPIO_RAM
static struct gpio_reg *gpio2reg(u32 gpio)
{
    if (gpio > IO_MAX_NUM) {
        return NULL;
    }
    return (struct gpio_reg *)gpio_regs[gpio / IO_GROUP_NUM];
}
#define USB_DP_OUT(x)    (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(0)) | ((x & 0x1) << 0)))
#define USB_DM_OUT(x)    (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(1)) | ((x & 0x1) << 1)))
#define USB_DP_DIR(x)    (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(2)) | ((x & 0x1) << 2)))
#define USB_DM_DIR(x)    (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(3)) | ((x & 0x1) << 3)))
#define USB_DP_PD(x)     (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(4)) | ((x & 0x1) << 4)))
#define USB_DM_PD(x)     (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(5)) | ((x & 0x1) << 5)))
#define USB_DP_PU(x)     (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(6)) | ((x & 0x1) << 6)))
#define USB_DM_PU(x)     (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(7)) | ((x & 0x1) << 7)))
#define USB_DP_DIE(x)    (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(9)) | ((x & 0x1) << 9)))
#define USB_DM_DIE(x)    (JL_USB_IO->CON0 = ((JL_USB_IO->CON0 & ~BIT(10)) | ((x & 0x1) << 10)))

#define USB_DP_IN()       (JL_USB->CON0 & BIT(17))
#define USB_DM_IN()       (JL_USB->CON0 & BIT(16))

__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 usb_set_direction(u32 gpio, u32 value)
{
    gpio -= USB_IO_OFFSET;
    if (value) {
        JL_USB_IO->CON0 |= BIT(gpio + 2);
    } else {
        JL_USB_IO->CON0 &= ~BIT(gpio + 2);
    }
    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 usb_output(u32 gpio, u32 value)
{
    gpio -= USB_IO_OFFSET;
    if (value) {
        JL_USB_IO->CON0 |= BIT(gpio);
    } else {
        JL_USB_IO->CON0 &= ~BIT(gpio);
    }
    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 usb_set_pull_up(u32 gpio, u32 value)
{
    gpio -= USB_IO_OFFSET;
    if (value) {
        JL_USB_IO->CON0 |= BIT(gpio + 6);
    } else {
        JL_USB_IO->CON0 &= ~BIT(gpio + 6);
    }
    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 usb_set_pull_down(u32 gpio, u32 value)
{
    gpio -= USB_IO_OFFSET;
    if (value) {
        JL_USB_IO->CON0 |= BIT(gpio + 4);
    } else {
        JL_USB_IO->CON0 &= ~BIT(gpio + 4);
    }
    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 usb_set_die(u32 gpio, u32 value)
{
    gpio -= USB_IO_OFFSET;
    if (value) {
        JL_USB_IO->CON0 |= BIT(gpio + 9);
    } else {
        JL_USB_IO->CON0 &= ~BIT(gpio + 9);
    }
    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 usb_set_dieh(u32 gpio, u32 value)
{
    gpio -= USB_IO_OFFSET;
    if (value) {
        JL_USB_IO->CON0 |= BIT(gpio + 13);
    } else {
        JL_USB_IO->CON0 &= ~BIT(gpio + 13);
    }
    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 usb_read(u32 gpio)
{
    gpio -= USB_IO_OFFSET;
    u32 v = JL_USB->CON0 & (BIT(17 - gpio));
    return !!v;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
void usb_iomode(u32 enable)
{
    if (enable) {
        JL_USB->CON0 &= ~BIT(0); // USB_PHY_OFF
        JL_USB_IO->CON0 |= BIT(11) | BIT(8);
    } else {
        JL_USB_IO->CON0 &= ~(BIT(11) | BIT(8));
    }
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
int gpio_set_direction(u32 gpio, u32 dir)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            usb_iomode(1);
            usb_set_direction(gpio - IO_MAX_NUM, dir);
        } else {
            PORTR_DIR(gpio - IO_MAX_NUM, dir);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (gpio == MIC_HW_IO) {
            if (g->out & mask) {
                audio_adc_mic_ctl(1);
            } else {
                audio_adc_mic_ctl(0);
            }
            g->dir &= ~mask;
            return 0;
        }
    }

    spin_lock(&lock);
    if (dir) {
        g->dir |= mask;
    } else {
        g->dir &= ~mask;
    }
    spin_unlock(&lock);

    return 0;
}

__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
int gpio_set_output_value(u32 gpio, u32 value)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            usb_output(gpio - IO_MAX_NUM, value);
        } else {
            PORTR_OUT(gpio - IO_MAX_NUM, value);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (gpio == MIC_HW_IO) {
            if ((g->out & mask) || (value)) {
                audio_adc_mic_ctl(1);
            }
            g->dir &= ~mask;
        }
    }

    spin_lock(&lock);
    if (value == 1) {
        g->out |= mask;
    } else {
        g->out &= ~mask;
    }
    spin_unlock(&lock);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (gpio == MIC_HW_IO) {
            if (!value) {
                audio_adc_mic_ctl(0);
            }
        }
    }

    return 0;
}

__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
int gpio_direction_input(u32 gpio)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            usb_iomode(1);
            usb_set_direction(gpio - IO_MAX_NUM, 1);
        } else {
            PORTR_DIR(gpio - IO_MAX_NUM, 1);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (gpio == MIC_HW_IO) {
            if (g->out & mask) {
                audio_adc_mic_ctl(1);
            } else {
                audio_adc_mic_ctl(0);
            }
            g->dir &= ~mask;
            return 0;
        }
    }

    spin_lock(&lock);
    g->dir |= mask;
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_dir(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op)
{
    struct gpio_reg *g;
    start = start > gpio ? start - gpio : start;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    usb_set_direction(GPIOUSB + i, 1);
                } else {
                    usb_set_direction(GPIOUSB + i, 0);
                }
            }
        } else {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    PORTR_DIR(GPIOR + i, 1);
                } else {
                    PORTR_DIR(GPIOR + i, 0);
                }
            }
        }
        return -EINVAL;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    spin_lock(&lock);
    u32 sfr = g->dir;
    switch (op) {
        case GPIO_SET:
            SFR(sfr, start, len, dat);
            break;
        case GPIO_AND:
            sfr &= (dat << start);
            break;
        case GPIO_OR:
            sfr |= (dat << start);
            break;
        case GPIO_XOR:
            sfr ^= (dat << start);
            break;
    }

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        struct gpio_reg *mic_g = gpio2reg(MIC_HW_IO);
        u32 mic_mask = __gpio_mask(MIC_HW_IO);
        if (((u32)g == (u32)mic_g) && (mic_mask >= BIT(start)) && (mic_mask <= BIT(start + len))) {
            sfr &= ~mic_mask;
            if (mic_g->out & mic_mask) {
                audio_adc_mic_ctl(1);
            } else {
                audio_adc_mic_ctl(0);
            }
        }
    }

    g->dir = sfr;
    spin_unlock(&lock);

    return 0;
}
void io_test()
{
    int ret = 0;
    while (1) {
        ret ^= 1;
        gpio_direction_output(IO_PORTA_05, ret);
    }
}

__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
int gpio_direction_output(u32 gpio, int value)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            usb_set_direction(gpio - IO_MAX_NUM, 0);
            usb_output(gpio - IO_MAX_NUM, value);
        } else {
            PORTR_DIR(gpio - IO_MAX_NUM, 0);
            PORTR_OUT(gpio - IO_MAX_NUM, value);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (gpio == MIC_HW_IO) {
            if ((g->out & mask) || (value)) {
                audio_adc_mic_ctl(1);
            }
            g->dir &= ~mask;
        }
    }

    spin_lock(&lock);
    if (value == 1) {
        g->out |= mask;
    } else if (value == 0) {
        g->out &= ~mask;
    }
    g->dir &= ~mask;
    spin_unlock(&lock);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (gpio == MIC_HW_IO) {
            if (!value) {
                audio_adc_mic_ctl(0);
            }
        }
    }
    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_write(u32 gpio, u32 value)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            usb_output(gpio - IO_MAX_NUM, value);
        } else {
            PORTR_OUT(gpio - IO_MAX_NUM, value);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (gpio == MIC_HW_IO) {
            if ((g->out & mask) || (value)) {
                audio_adc_mic_ctl(1);
            }
            g->dir &= ~mask;
        }
    }

    spin_lock(&lock);
    if (value == 1) {
        g->out |= mask;
    } else if (value == 0) {
        g->out &= ~mask;
    }
    spin_unlock(&lock);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (gpio == MIC_HW_IO) {
            if (!value) {
                audio_adc_mic_ctl(0);
            }
        }
    }
    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_out(u32 gpio, u32 start, u32 len, u32 dat)
{
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    start = start > gpio ? start - gpio : start;
    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    usb_output(GPIOUSB + i, 1);
                } else {
                    usb_output(GPIOUSB + i, 0);
                }
            }
        } else {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    PORTR_OUT(GPIOR + i, 1);
                } else {
                    PORTR_OUT(GPIOR + i, 0);
                }
            }
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    spin_lock(&lock);
    u32 sfr = g->out;
    SFR(sfr, start, len, dat);

    struct gpio_reg *mic_g;
    u32 mic_mask;
    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        mic_g = gpio2reg(MIC_HW_IO);
        mic_mask = __gpio_mask(MIC_HW_IO);
        if (((u32)g == (u32)mic_g) && (mic_mask >= BIT(start)) && (mic_mask <= BIT(start + len))) {
            if ((mic_g->out & mic_mask) || (sfr & mic_mask)) {
                audio_adc_mic_ctl(1);
            }
            mic_g->dir &= ~mic_mask;
        }
    }

    g->out = sfr;
    spin_unlock(&lock);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (((u32)g == (u32)mic_g) && (mic_mask >= BIT(start)) && (mic_mask <= BIT(start + len))) {
            if (!(g->out & mic_mask)) {
                audio_adc_mic_ctl(0);
            }
        }
    }
    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
int gpio_read(u32 gpio)
{
    u32 mask;
    u32 v;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            return usb_read(gpio - IO_MAX_NUM);
        }
        return PORTR_IN(gpio - IO_MAX_NUM);
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);

    spin_lock(&lock);
    if (g->dir & mask) {
        v = !!(g->in & mask);
        printf("g->in:%x\n", g->in);
    } else {
        v = !!(g->out & mask);
    }
    spin_unlock(&lock);

    return v;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_in(u32 gpio)
{
    u32 mask;
    struct gpio_reg *g;
    u32 v = 0;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            return usb_read(GPIOUSB + 0) | (usb_read(GPIOUSB + 1) << 1);
        }
        for (int i = 0; i < 3; i++) {
            v = (!!PORTR_IN(GPIOR + i)) << i;
        }
        return v;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);

    spin_lock(&lock);
    v = g->in;
    spin_unlock(&lock);

    return v;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
int gpio_set_pull_up(u32 gpio, int value)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            usb_set_pull_up(gpio - IO_MAX_NUM, value);
        } else {
            PORTR_PU(gpio - IO_MAX_NUM, value);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);
    spin_lock(&lock);
    if (value) {
        g->pu |= mask;
    } else {
        g->pu &= ~mask;
    }
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_set_pu(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op)
{
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    start = start > gpio ? start - gpio : start;
    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    usb_set_pull_up(GPIOUSB + i, 1);
                } else {
                    usb_set_pull_up(GPIOUSB + i, 0);
                }
            }
        } else {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    PORTR_PU(GPIOR + i, 1);
                } else {
                    PORTR_PU(GPIOR + i, 0);
                }
            }
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    spin_lock(&lock);
    u32 sfr = g->pu;
    switch (op) {
        case GPIO_SET:
            SFR(sfr, start, len, dat);
            break;
        case GPIO_AND:
            sfr &= (dat << start);
            break;
        case GPIO_OR:
            sfr |= (dat << start);
            break;
        case GPIO_XOR:
            sfr ^= (dat << start);
            break;
    }

    g->pu = sfr;
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
int gpio_set_pull_down(u32 gpio, int value)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            usb_set_pull_down(gpio - IO_MAX_NUM, value);
        } else {
            PORTR_PD(gpio - IO_MAX_NUM, value);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);
    spin_lock(&lock);
    if (value) {
        g->pd |= mask;
    } else {
        g->pd &= ~mask;
    }
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_set_pd(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op)
{
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    start = start > gpio ? start - gpio : start;
    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    usb_set_pull_down(GPIOUSB + i, 1);
                } else {
                    usb_set_pull_down(GPIOUSB + i, 0);
                }
            }
        } else {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    PORTR_PD(GPIOR + i, 1);
                } else {
                    PORTR_PD(GPIOR + i, 0);
                }
            }
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    spin_lock(&lock);
    u32 sfr = g->pd;
    switch (op) {
        case GPIO_SET:
            SFR(sfr, start, len, dat);
            break;
        case GPIO_AND:
            sfr &= (dat << start);
            break;
        case GPIO_OR:
            sfr |= (dat << start);
            break;
        case GPIO_XOR:
            sfr ^= (dat << start);
            break;
    }
    g->pd = sfr;
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_set_hd0(u32 gpio, u32 value)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            return -EINVAL;
        } else {
            PORTR_HD0(gpio - IO_MAX_NUM, value);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);
    spin_lock(&lock);
    if (value) {
        g->hd0 |= mask;
    } else {
        g->hd0 &= ~mask;
    }
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
int gpio_set_hd(u32 gpio, int value)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            return -EINVAL;
        } else {
            PORTR_HD(gpio - IO_MAX_NUM, value);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);
    spin_lock(&lock);
    if (value) {
        g->hd |= mask;
    } else {
        g->hd &= ~mask;
    }
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
int gpio_set_die(u32 gpio, int value)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            usb_set_die(gpio - IO_MAX_NUM, value);
        } else {
            PORTR_DIE(gpio - IO_MAX_NUM, value);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        if (gpio == MIC_HW_IO) {
            g->pu  &= ~mask;
            g->out &= ~mask;
            g->dir &= ~mask;
            g->die |= mask;
            audio_adc_mic_ctl(0);
            return 0;
        }
    }

    spin_lock(&lock);
    if (value) {
        g->die |= mask;
    } else {
        g->die &= ~mask;
    }
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_set_dieh(u32 gpio, u32 value)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            usb_set_dieh(gpio - IO_MAX_NUM, value);
        } else {
            PORTR_DIEH(gpio - IO_MAX_NUM, value);
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    mask = __gpio_mask(gpio);
    spin_lock(&lock);
    if (value) {
        g->dieh |= mask;
    } else {
        g->dieh &= ~mask;
    }
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_die(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op)
{
    struct gpio_reg *g;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    start = start > gpio ? start - gpio : start;
    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    usb_set_die(GPIOUSB + i, 1);
                } else {
                    usb_set_die(GPIOUSB + i, 0);
                }
            }
        } else {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    PORTR_DIE(GPIOR + i, 1);
                } else {
                    PORTR_DIE(GPIOR + i, 0);
                }
            }
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    spin_lock(&lock);
    u32 sfr = g->die;
    switch (op) {
        case GPIO_SET:
            SFR(sfr, start, len, dat);
            break;
        case GPIO_AND:
            sfr &= (dat << start);
            break;
        case GPIO_OR:
            sfr |= (dat << start);
            break;
        case GPIO_XOR:
            sfr ^= (dat << start);
            break;
    }

    if (CHIP_VER >= CHIP_VER_D) {
    } else {
        struct gpio_reg *mic_g = gpio2reg(MIC_HW_IO);
        u32 mic_mask = __gpio_mask(MIC_HW_IO);
        if (((u32)g == (u32)mic_g) && (mic_mask >= BIT(start)) && (mic_mask <= BIT(start + len))) {
            mic_g->pu  &= ~mic_mask;
            mic_g->out &= ~mic_mask;
            mic_g->dir &= ~mic_mask;
            sfr |= mic_mask;
            audio_adc_mic_ctl(0);
        }
    }

    g->die = sfr;
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args))
AT_GPIO_RAM
u32 gpio_dieh(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op)
{
    struct gpio_reg *g;

    start = start > gpio ? start - gpio : start;

    if (gpio > IO_PORT_MAX) {
        return -EINVAL;
    }

    if (gpio >= IO_MAX_NUM) {
        if (gpio >= IO_PORT_DP) {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    usb_set_dieh(GPIOUSB + i, 1);
                } else {
                    usb_set_dieh(GPIOUSB + i, 0);
                }
            }
        } else {
            for (int i = start ; i < len ; i++) {
                if (dat & BIT(i)) {
                    PORTR_DIEH(GPIOR + i, 1);
                } else {
                    PORTR_DIEH(GPIOR + i, 0);
                }
            }
        }
        return 0;
    }

    g = gpio2reg(gpio);
    if (!g) {
        return -EINVAL;
    }

    spin_lock(&lock);
    u32 sfr = g->dieh;
    switch (op) {
        case GPIO_SET:
            SFR(sfr, start, len, dat);
            break;
        case GPIO_AND:
            sfr &= (dat << start);
            break;
        case GPIO_OR:
            sfr |= (dat << start);
            break;
        case GPIO_XOR:
            sfr ^= (dat << start);
            break;
    }
    g->dieh = sfr;
    spin_unlock(&lock);

    return 0;
}
__attribute__((always_inline_when_const_args)) u32 gpio_output_channle(u32 gpio, u32 clk)
{
    u32 ch = clk / 0x10;
    clk = clk % 0x10;

    switch (ch) {
        case 0 :
            JL_IOMAP->CON1 &= ~(0xf << 8);
            JL_IOMAP->CON1 |= clk << 8;
            break;
        case 1:
        case 2:
            JL_IOMAP->CON3 &= ~(0xf << (20 + (ch - 1) * 4));
            JL_IOMAP->CON3 |= clk << (20 + (ch - 1) * 4);
            break;
        default:
            return -EINVAL;
    }

    gpio_set_pull_up(gpio, 1);
    gpio_set_pull_down(gpio, 1);
    switch (ch) {
        case 0:
            gpio_direction_output(gpio, 0);
            gpio_set_die(gpio, 0);
            break;
        case 1:
            gpio_direction_output(gpio, 0);
            gpio_set_die(gpio, 1);
            break;
        case 2:
            gpio_direction_output(gpio, 1);
            gpio_set_die(gpio, 0);
            break;
        case 3:
            gpio_direction_output(gpio, 1);
            gpio_set_die(gpio, 1);
            break;
        default:
            return -EINVAL;
    }

    return 0;
}

__attribute__((always_inline_when_const_args)) u32 gpio_wakeup0(u32 gpio)
{
    if (gpio > IO_PORT_DM) {
        return -EINVAL;
    }

    if (gpio > IO_PORTD_07 && gpio < IO_PORT_DP) {
        return -EINVAL;
    }
    JL_IOMAP->CON2 &= ~(0b111111 << 0);
    JL_IOMAP->CON2 |= gpio;
    return 0;
}
__attribute__((always_inline_when_const_args)) u32 gpio_irflt_in(u32 gpio)
{
    if (gpio > IO_PORT_DM) {
        return -EINVAL;
    }

    if (gpio > IO_PORTD_07 && gpio < IO_PORT_DP) {
        return -EINVAL;
    }
    JL_IOMAP->CON2 &= ~(0b111111 << 8);
    JL_IOMAP->CON2 |= gpio << 8;
    return 0;
}
__attribute__((always_inline_when_const_args)) u32 gpio_cap_mux(u32 gpio)
{
    if (gpio > IO_PORT_DM) {
        return -EINVAL;
    }

    if (gpio > IO_PORTD_07 && gpio < IO_PORT_DP) {
        return -EINVAL;
    }
    JL_IOMAP->CON2 &= ~(0b111111 << 16);
    JL_IOMAP->CON2 |= gpio << 16;
    return 0;
}
__attribute__((always_inline_when_const_args)) u32 gpio_uart_rx_input(u32 gpio, u32 ut, u32 ch)
{
    u32 mask;
    struct gpio_reg *g;

    if (gpio > IO_PORT_DM) {
        return -EINVAL;
    }

    if (gpio > IO_PORTD_07 && gpio < IO_PORT_DP) {
        return -EINVAL;
    }

    if (gpio < IO_MAX_NUM) {
        g = gpio2reg(gpio);
        if (!g) {
            return -EINVAL;
        }
    }

    switch (ut) {
        case 0:
            JL_IOMAP->CON3 &= ~(0b111 << 0);
            JL_IOMAP->CON3 |= ((0b100 + ch) << 0);
            break;
        case 1:
            JL_IOMAP->CON3 &= ~(0b111 << 4);
            JL_IOMAP->CON3 |= ((0b100 + ch) << 4);
            break;
        case 2:
            JL_IOMAP->CON3 &= ~(0b111 << 8);
            JL_IOMAP->CON3 |= ((0b100 + ch) << 8);
            break;
        default:
            return -EINVAL;
    }

    switch (ch) {
        case 0 :
            JL_IOMAP->CON2 &= ~(0b111111 << 0);
            JL_IOMAP->CON2 |= gpio << 0;
            break;
        case 1 :
            JL_IOMAP->CON2 &= ~(0b111111 << 8);
            JL_IOMAP->CON2 |= gpio << 8;
            break;
        case 2 :
            JL_IOMAP->CON2 &= ~(0b111111 << 16);
            JL_IOMAP->CON2 |= gpio << 16;
            break;
        case 3:
            JL_IOMAP->CON2 &= ~(0b111111 << 24);
            JL_IOMAP->CON2 |= gpio << 24;
            break;
        default :
            return -EINVAL;
    }

    if (gpio >= IO_PORT_DP) {
        usb_iomode(1);
        usb_set_die(gpio - IO_MAX_NUM, 1);
        usb_set_direction(gpio - IO_MAX_NUM, 1); // 作为输入模式
        usb_set_pull_up(gpio - IO_MAX_NUM, 0); // 不下拉
        usb_set_pull_down(gpio - IO_MAX_NUM, 0); // 不上拉
    } else {
        mask = __gpio_mask(gpio);
        spin_lock(&lock);
        g->pd  &= ~mask;
        g->pu  &= ~mask;
        g->die |= mask;
        g->dir |= mask;
        spin_unlock(&lock);
    }

    return 0;
}
__attribute__((always_inline_when_const_args)) u32 gpio_close_uart0(void)
{
    u8 ch ;
    ch = (JL_IOMAP->CON0 >> 6) & 3;
    switch (ch) {
        case 0 :
            gpio_set_direction(IO_PORTA_05, 1);
            gpio_set_die(IO_PORTA_05, 0);
            gpio_set_direction(IO_PORTA_06, 1);
            gpio_set_pull_up(IO_PORTA_06, 0);
            gpio_set_die(IO_PORTA_06, 0);
            break;
        case 1:
            gpio_set_direction(IO_PORTB_04, 1);
            gpio_set_die(IO_PORTB_04, 0);
            gpio_set_direction(IO_PORTB_06, 1);
            gpio_set_pull_up(IO_PORTB_06, 0);
            gpio_set_die(IO_PORTB_06, 0);
            break;
        case 2:
            gpio_set_hd(IO_PORTB_05, 0);
            gpio_set_direction(IO_PORTB_05, 1);
            gpio_set_pull_up(IO_PORTB_05, 0);
            gpio_set_die(IO_PORTB_05, 0);
            break;
        case 3 :
            gpio_set_direction(IO_PORTA_11, 1);
            gpio_set_die(IO_PORTA_11, 0);
            gpio_set_direction(IO_PORTA_12, 1);
            gpio_set_pull_up(IO_PORTA_12, 0);
            gpio_set_die(IO_PORTA_12, 0);
            break;
        default:
            return -EINVAL;
    }
    return 0;
}

__attribute__((always_inline_when_const_args)) u32 gpio_close_uart1(void)
{
    u8 ch ;
    ch = (JL_IOMAP->CON1 >> 2) & 3;
    switch (ch) {
        case 0 :
            gpio_set_direction(IO_PORTB_00, 1);
            gpio_set_die(IO_PORTB_00, 0);
            gpio_set_direction(IO_PORTB_01, 1);
            gpio_set_pull_up(IO_PORTB_01, 0);
            gpio_set_die(IO_PORTB_01, 0);
            break;
        case 1 :
            gpio_set_direction(IO_PORTC_00, 1);
            gpio_set_die(IO_PORTC_00, 0);
            gpio_set_direction(IO_PORTC_01, 1);
            gpio_set_pull_up(IO_PORTC_01, 0);
            gpio_set_die(IO_PORTC_01, 0);
            break;
        case 2 :
            gpio_set_direction(IO_PORTA_00, 1);
            gpio_set_die(IO_PORTA_00, 0);
            gpio_set_direction(IO_PORTA_01, 1);
            gpio_set_pull_up(IO_PORTA_01, 0);
            gpio_set_die(IO_PORTA_01, 0);
            break;
        case 3:
            usb_iomode(0);
            break;
        default:
            return -EINVAL;
    }
    return 0;
}

__attribute__((always_inline_when_const_args)) u32 gpio_close_uart2(void)
{
    u8 ch ;
    ch = (JL_IOMAP->CON1 >> 14) & 3;
    switch (ch) {
        case 0 :
            gpio_set_direction(IO_PORTA_02, 1);
            gpio_set_die(IO_PORTA_02, 0);
            gpio_set_direction(IO_PORTA_03, 1);
            gpio_set_pull_up(IO_PORTA_03, 0);
            gpio_set_die(IO_PORTA_03, 0);
            break;
        case 1 :
            gpio_set_direction(IO_PORTA_09, 1);
            gpio_set_die(IO_PORTA_09, 0);
            gpio_set_direction(IO_PORTA_10, 1);
            gpio_set_pull_up(IO_PORTA_10, 0);
            gpio_set_die(IO_PORTA_10, 0);
            break;
        case 2 :
            gpio_set_direction(IO_PORTB_09, 1);
            gpio_set_die(IO_PORTB_09, 0);
            gpio_set_direction(IO_PORTB_10, 1);
            gpio_set_pull_up(IO_PORTB_10, 0);
            gpio_set_die(IO_PORTB_10, 0);
            break;
        case 3 :
            gpio_set_direction(IO_PORTC_04, 1);
            gpio_set_die(IO_PORTC_04, 0);
            gpio_set_direction(IO_PORTC_05, 1);
            gpio_set_pull_up(IO_PORTC_05, 0);
            gpio_set_die(IO_PORTC_05, 0);
            break;
        default:
            return -EINVAL;
    }
    return 0;
}

__attribute__((always_inline_when_const_args)) u32 gpio_set_uart0(u32 ch)
{
    if (ch > 3) {
        JL_IOMAP->CON3 &= ~BIT(3); // UT0IOEN
    } else {
        JL_IOMAP->CON3 |= BIT(3); // UT0IOEN
        JL_IOMAP->CON3 &= ~BIT(2); // UT0IOEN
        JL_IOMAP->CON0 &= ~(3 << 6);
        JL_IOMAP->CON0 |= ch << 6;
        switch (ch) {
            case 0 :
                gpio_set_direction(IO_PORTA_05, 0);
                gpio_set_die(IO_PORTA_05, 1);
                gpio_set_direction(IO_PORTA_06, 1);
                gpio_set_pull_up(IO_PORTA_06, 1);
                gpio_set_die(IO_PORTA_06, 1);
                break;
            case 1:
                gpio_set_direction(IO_PORTB_04, 0);
                gpio_set_die(IO_PORTB_04, 1);
                gpio_set_direction(IO_PORTB_06, 1);
                gpio_set_pull_up(IO_PORTB_06, 1);
                gpio_set_die(IO_PORTB_06, 1);
                break;
            case 2:
                gpio_set_hd(IO_PORTB_05, 1);
                gpio_set_pull_up(IO_PORTB_05, 1);
                gpio_set_pull_down(IO_PORTB_05, 0);
                gpio_set_direction(IO_PORTB_05, 0);
                gpio_set_die(IO_PORTB_05, 1);
                break;
            case 3 :
                gpio_set_direction(IO_PORTA_11, 0);
                gpio_set_die(IO_PORTA_11, 1);
                gpio_set_direction(IO_PORTA_12, 1);
                gpio_set_pull_up(IO_PORTA_12, 1);
                gpio_set_die(IO_PORTA_12, 1);
                break;
            default:
                return -EINVAL;
        }
    }
    return 0;
}

__attribute__((always_inline_when_const_args)) u32 gpio_set_uart1(u32 ch)
{
    if (ch > 3) {
        JL_IOMAP->CON3 &= ~BIT(7); // UT1IOEN
    } else {
        JL_IOMAP->CON3 |= BIT(7); // UT1IOEN
        JL_IOMAP->CON3 &= ~BIT(6); // UT1IOEN
        JL_IOMAP->CON1 &= ~(3 << 2);
        JL_IOMAP->CON1 |= ch << 2;
        switch (ch) {
            case 0 :
                gpio_set_direction(IO_PORTB_00, 0);
                gpio_set_die(IO_PORTB_00, 1);
                gpio_set_direction(IO_PORTB_01, 1);
                gpio_set_pull_up(IO_PORTB_01, 1);
                gpio_set_die(IO_PORTB_01, 1);
                break;
            case 1 :
                gpio_set_direction(IO_PORTC_00, 0);
                gpio_set_die(IO_PORTC_00, 1);
                gpio_set_direction(IO_PORTC_01, 1);
                gpio_set_pull_up(IO_PORTC_01, 1);
                gpio_set_die(IO_PORTC_01, 1);
                break;
            case 2:
                gpio_set_direction(IO_PORTA_00, 0);
                gpio_set_die(IO_PORTA_00, 1);
                gpio_set_direction(IO_PORTA_01, 1);
                gpio_set_pull_up(IO_PORTA_01, 1);
                gpio_set_die(IO_PORTA_01, 1);
                break;
            case 3:
                usb_iomode(1);
                // tx dp
                usb_set_die(IO_PORT_DP - IO_MAX_NUM, 1);
                usb_set_direction(IO_PORT_DP - IO_MAX_NUM, 0);
                usb_set_pull_up(IO_PORT_DP - IO_MAX_NUM, 0);
                usb_set_pull_down(IO_PORT_DP - IO_MAX_NUM, 0);

                // rx dm
                usb_set_die(IO_PORT_DM - IO_MAX_NUM, 1);
                usb_set_direction(IO_PORT_DM - IO_MAX_NUM, 1);
                usb_set_pull_up(IO_PORT_DM - IO_MAX_NUM, 1);
                usb_set_pull_down(IO_PORT_DM - IO_MAX_NUM, 0);

                break;
            default:
                return -EINVAL;
        }
    }
    return 0;
}
__attribute__((always_inline_when_const_args)) u32 gpio_set_uart2(u32 ch)
{
    if (ch > 3) {
        JL_IOMAP->CON3 &= ~BIT(11); // UT2IOEN
    } else {
        JL_IOMAP->CON3 |= BIT(11); // UT2IOEN
        JL_IOMAP->CON3 &= ~BIT(10); // UT2IOEN
        JL_IOMAP->CON1 &= ~(3 << 14);
        JL_IOMAP->CON1 |= ch << 14;
        switch (ch) {
            case 0 :
                gpio_set_direction(IO_PORTA_02, 0);
                gpio_set_die(IO_PORTA_02, 1);
                gpio_set_direction(IO_PORTA_03, 1);
                gpio_set_pull_up(IO_PORTA_03, 1);
                gpio_set_die(IO_PORTA_03, 1);
                break;
            case 1 :
                gpio_set_direction(IO_PORTA_09, 0);
                gpio_set_die(IO_PORTA_09, 1);
                gpio_set_direction(IO_PORTA_10, 1);
                gpio_set_pull_up(IO_PORTA_10, 1);
                gpio_set_die(IO_PORTA_10, 1);
                break;
            case 2 :
                gpio_set_direction(IO_PORTB_09, 0);
                gpio_set_die(IO_PORTB_09, 1);
                gpio_set_direction(IO_PORTB_10, 1);
                gpio_set_pull_up(IO_PORTB_10, 1);
                gpio_set_die(IO_PORTB_10, 1);
                break;
            case 3 :
                gpio_set_direction(IO_PORTC_04, 0);
                gpio_set_die(IO_PORTC_04, 1);
                gpio_set_direction(IO_PORTC_05, 1);
                gpio_set_pull_up(IO_PORTC_05, 1);
                gpio_set_die(IO_PORTC_05, 1);
                break;
            default:
                return -EINVAL;
        }
    }
    return 0;
}
__attribute__((always_inline_when_const_args)) u32 gpio_irflt_to_timer(u32 t)
{
    JL_IOMAP->CON0 &= (~(0b111 << 8));
    JL_IOMAP->CON0 |= (BIT(10) | (t << 8));
    return 0;
}

__attribute__((always_inline_when_const_args)) u32 get_gpio(const char *p)
{
    u32 port;
    if (p[0] == 'P') {
        if (p[1] >= 'A' && p[1] <= 'H') {
            port = p[1] - 'A';
            port *= IO_GROUP_NUM;
        } else if (p[1] == 'R') {
            port = IO_PORT_PR_00;
        } else {
            return -EINVAL;
        }

        int mask = (p[2] - '0') * 10 + (p[3] - '0');
        if (mask < 16) {
            port += mask;
            return port;
        }
    }
    if (strcmp(p, "USBDP") == 0) {
        return  IO_PORT_DP;
    }

    if (strcmp(p, "USBDM") == 0) {
        return  IO_PORT_DM;
    }
    return -EINVAL;
}

void gpio_longpress_pin0_reset_config(u32 pin, u32 time, u32 level)
{
    if (time) {
        gpio_set_dieh(pin, 1);
        gpio_set_die(pin, 1);
        gpio_set_direction(pin, 1);

        if (level) {
            gpio_set_pull_up(pin, 0);
            gpio_set_pull_down(pin, 1);
        } else {
            gpio_set_pull_up(pin, 1);
            gpio_set_pull_down(pin, 0);
        }

        switch (time) {
            case 1:
                time = 0;
                break;
            case 2:
                time = 1;
                break;
            case 4:
                time = 2;
                break;
            case 8:
                time = 3;
                break;
        }

        u32 port_val = 0xFF;

        if (pin >= IO_MAX_NUM) {
            if (pin == IO_PORT_DP) {
                port_val = 56;
            } else if (pin == IO_PORT_DM) {
                port_val = 57;
            }
        } else {
            port_val = pin;
        }
        if (port_val != 0xFF) {
            p33_tx_1byte(P3_PORT_SEL10, pin);
            p33_or_1byte(P3_PINR_CON, (time << 4) | (level << 2) | BIT(0));
        } else {
            return;
        }
    } else {
        p33_tx_1byte(P3_PINR_CON, 0);
    }
}

void gpio_shortpress_reset_config(u32 enable)
{
    if (enable) {
        p33_or_1byte(P3_ANA_CON2, BIT(3));
    } else {
        p33_and_1byte(P3_ANA_CON2, ~BIT(3));
    }
}

AT(.volatile_ram_code)
__attribute__((always_inline_when_const_args)) u32 spi_get_port(void)
{
    // sfc port
    return (JL_IOMAP->CON1 >> 5) & 0x1;
}
